// update.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "types.h"
#include <ctype.h>
#include <unistd.h>
#include "egon_def.h"
#include "check.h"

#define  MAX_PATH             (260)
#define  ALIGN_SIZE  0x1000
#define  BOOT1_MAGIC                     "eGON.BT"

void *script_file_decode(char *script_name);
int merge_uboot(char *source_uboot_name, char *script_name);
int genchecksum_for_boot(char *boot_name, char *dest_file);
//------------------------------------------------------------------------------------------------------------
//
// 函数说明
//
//
// 参数说明
//
//
// 返回值
//
//
// 其他
//    无
//
//------------------------------------------------------------------------------------------------------------
int IsFullName(const char *FilePath)
{
    if (isalpha(FilePath[0]) && ':' == FilePath[1])
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
//------------------------------------------------------------------------------------------------------------
//
// 函数说明
//
//
// 参数说明
//
//
// 返回值
//
//
// 其他
//    无
//
//------------------------------------------------------------------------------------------------------------
void GetFullPath(char *dName, const char *sName)
{
    char Buffer[MAX_PATH];

	if(IsFullName(sName))
	{
	    strcpy(dName, sName);
		return ;
	}

   /* Get the current working directory: */
   if(getcwd(Buffer, MAX_PATH ) == NULL)
   {
        perror( "getcwd error" );
        return ;
   }
   sprintf(dName, "%s/%s", Buffer, sName);
}

//------------------------------------------------------------------------------------------------------------
//
// 函数说明
//
//
// 参数说明
//
//
// 返回值
//
//
// 其他
//    无
//
//------------------------------------------------------------------------------------------------------------
void Usage(void)
{
	printf("\n");
	printf("Usage:\n");
	printf("update.exe script file path para file path\n\n");
}

int main(int argc, char* argv[])
{
	char   str1[] = "D:\\winners\\eBase\\eGON\\EGON2_TRUNK\\boot_23\\workspace\\eGon\\boot1.bin";
	char   str2[] = "D:\\winners\\eBase\\eGON\\EGON2_TRUNK\\boot_23\\workspace\\wboot\\bootfs\\script.bin";
	char   source_boot_name[MAX_PATH];
	char   dest_boot_name[MAX_PATH];
//	int    source_length, script_length;
//	int    total_length;
//	char   *pbuf_source, *pbuf_script;

	if(argc == 3)
	{
		if(argv[1] == NULL)
		{
			printf("update error: one of the input file names is empty\n");

			return __LINE__;
		}
	}
	else
	{
		Usage();

		return __LINE__;
	}
	GetFullPath(source_boot_name,  argv[1]);
	GetFullPath(dest_boot_name,  argv[2]);

	printf("\n");
	printf("source file Path=%s\n", source_boot_name);
	printf("dest file Path=%s\n", dest_boot_name);
	printf("\n");
    if((access(dest_boot_name, F_OK)) != -1)
    {
        printf("file %s exist.\n", dest_boot_name);
        unlink(dest_boot_name);
    }
    else
    {
        printf("file %s not exist.\n", dest_boot_name);
    }
	//读取原始boot
	if(genchecksum_for_boot(source_boot_name, dest_boot_name))
	{
		printf("update uboot error: update error\n");

		return -1;
	}

	return 0;

}
//find string in string, return the first start location or -1 if can not find
int StringFind(const char *pSrc, const char *pDst, int n)
{
	int i, j;
	for (i=0; i < n; i++)
	{
		if(pSrc[i]!=pDst[0])
			continue;
		j = 0;
		while(pDst[j]!='\0' && pSrc[i+j]!='\0')
		{
			j++;
			if(pDst[j]!=pSrc[i+j])
                break;
		}
		if(pDst[j]=='\0')
			return i;
	}
	return -1;
}

int genchecksum_for_boot(char *boot_name, char *dest_file)
{
	FILE *boot_file = NULL, *dest_fd = NULL;
	boot_file_head_t  *boot_head;
	char *boot_buf = NULL;
	int   i;
	int   ret = -1;
	int   boot_length;
	int   origin_length;
	char  buffer[512] = {0};

	boot_file = fopen(boot_name, "rb+");
	if(boot_file == NULL)
	{
		printf("gencheck error : unable to open boot file\n");
		goto _err_uboot_out;
	}
	fseek(boot_file, 0, SEEK_END);
	origin_length = ftell(boot_file);
	fseek(boot_file, 0, SEEK_SET);
	if(!origin_length)
	{
		printf("update uboot error : uboot length is zero\n");
		goto _err_uboot_out;
	}
    printf("origin_length=%d [0x%x]\n", origin_length, origin_length);
	//获取对齐尺寸
	fread(buffer, 512, 1, boot_file);

    ret = StringFind(buffer, BOOT1_MAGIC, 60);
    if(ret != -1)
    {
        printf("find eGON.BT = %d\n", ret);
        printf("find header = %x\n", buffer[ret - 4]);
    }
    else
    {
        printf("not find eGON.BT\n");
		goto _err_uboot_out;
    }

	boot_head = (boot_file_head_t *)&buffer[ret - 4];
    origin_length = origin_length -ret + 4;
    printf("origin_length=%d [0x%x]\n", origin_length, origin_length);
	boot_length = origin_length;
	if(origin_length & (ALIGN_SIZE - 1))
	{
		boot_length = (origin_length + ALIGN_SIZE) & (~(ALIGN_SIZE - 1));
	}
    if(boot_length < 0x6000)
        boot_length = 0x6000;  // boot0 = 24k
    printf("boot_length=%d [0x%x]\n", boot_length, boot_length);
    // printf("magic=%s\n", boot_head->magic);
    printf("check_sum=0x%x\n", boot_head->check_sum);
    printf("pub_head_size=%d\n", boot_head->pub_head_size);
    printf("length=%d\n", boot_head->length);
	//开辟空间
	boot_buf = (char *)malloc(boot_length);
	if(!boot_buf)
	{
		printf("update uboot error : fail to malloc memory for uboot\n");
		goto _err_uboot_out;
	}
	memset(boot_buf, 0xff, boot_length);
	rewind(boot_file);
	fseek(boot_file, ret - 4, SEEK_SET);
	fread(boot_buf, origin_length, 1, boot_file);
	//还原文件大小
	boot_head = (boot_file_head_t *)boot_buf;
	boot_head->length = boot_length;
	// boot_head->uboot_length = boot_length;
    // check_file(boot_buf, boot_head->check_sum, "eGON.BT1");
    check_sum(boot_buf, boot_head->length);
    //重新生成校验和
    gen_check_sum(boot_buf);

	dest_fd = fopen(dest_file, "wb+");
	if(dest_fd == NULL)
	{
		printf("genchecksum boot error : unable to open boot file\n");
		goto _err_uboot_out;
	}
	//写入文件
	rewind(dest_fd);
	fwrite(boot_buf, boot_length, 1, dest_fd);
	ret = 0;

_err_uboot_out:
	if(boot_buf)
	{
		free(boot_buf);
	}
	if(boot_file)
	{
		fclose(boot_file);
	}
	if(dest_fd)
	{
		fclose(dest_fd);
	}

	return ret;
}
